// // unique_lock example
// #include <iostream>       // std::cout
// #include <thread>         // std::thread
// #include <mutex>          // std::mutex, std::unique_lock

// std::mutex mtx;           // mutex for critical section

// void print_block (int n, char c) {
//   // critical section (exclusive access to std::cout signaled by lifetime of lck):
//   std::unique_lock<std::mutex> lck (mtx);
//   for (int i=0; i<n; ++i) { std::cout << c; }
//   std::cout << '\n';
// }

// int main ()
// {
//   std::thread th1 (print_block,50,'*');
//   std::thread th2 (print_block,50,'$');

//   th1.join();
//   th2.join();

//   return 0;
// }

#include <mutex>
#include <thread>
#include <chrono>
 
struct Box {
    explicit Box(int num) : num_things{num} {}
 
    int num_things;
    std::mutex m;
};
 
void transfer(Box &from, Box &to, int num)
{
    // 仍未实际取锁
    std::unique_lock<std::mutex> lock1(from.m, std::defer_lock);
    std::unique_lock<std::mutex> lock2(to.m, std::defer_lock);
 
    // 锁两个 unique_lock 而不死锁
    std::lock(lock1, lock2);
 
    from.num_things -= num;
    to.num_things += num;
 
    // 'from.m' 与 'to.m' 互斥解锁于 'unique_lock' 析构函数
}
 
int main()
{
    Box acc1(100);
    Box acc2(50);
 
    std::thread t1(transfer, std::ref(acc1), std::ref(acc2), 10);
    std::thread t2(transfer, std::ref(acc2), std::ref(acc1), 5);
 
    t1.join();
    t2.join();
}